package com.wfy.common.listener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;

import java.sql.*;

/**
 * 启动初始化监听器
 * ContextLoaderListener监听器的作用就是启动Web容器时，自动装配ApplicationContext的配置信息
 * Created with IntelliJ IDEA.
 * User: wangxindong
 * Date: 2017/9/29
 * Time: 12:49
 */
public class WebContextListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    // ================================================================
    // Constants
    // ================================================================

    private static final Logger LOGGER = LoggerFactory.getLogger(WebContextListener.class);

    // ================================================================
    // Fields
    // ================================================================


    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {

        LOGGER.info("系统初始化检测中...");

        /**
         * 检查mysql数据库状态
         */
        CheckMysqlSatus.check(event.getEnvironment());

    }

    // ================================================================
    // Public or Protected Methods
    // ================================================================


    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================


    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    /**
     * 检查mysql的运行状态
     */
    private static class CheckMysqlSatus {

        private static boolean check(ConfigurableEnvironment environment) {
            // mysql属于业务数据库，不启动会导致业务失败
            // 获取读取延时参数，默认是等待一个小时
            long now = System.currentTimeMillis();
            long start = now;
            // 60*1000;
            long timeout = -1;
            // 持续时间
            long contTime;
            boolean dbOk = false;
            // 等待时间,考虑以后加入配置文件
            String wait = "3600";
            long secTimeout = Long.parseLong(wait);
            if (secTimeout > 0)
                timeout = secTimeout * 1000;
            while (true) {
                if (checkDBState(environment)) {
                    dbOk = true;
                    break;
                }
                try {
                    LOGGER.info("database connection is error, wait for mysql database start!");
                    Thread.sleep(10000);
                } catch (Exception ignored) {
                }
                now = System.currentTimeMillis();
                contTime = now - start;
                if (timeout <= 0)
                    continue;
                if (contTime >= timeout)
                    break;
            }
            if (!dbOk) {
                LOGGER.info("database pool error ,please check mysql status...");
                return false;
            } else {
                LOGGER.info("database pool ok, mysql is running..");
            }
            return true;
        }

        /**
         * 获取mysql数据库状态
         */
        private static boolean checkDBState(ConfigurableEnvironment environment) {
            boolean succ;
            // 验证sql
            String sql = environment.getProperty("spring.datasource.validationQuery", "select 1");
            try {
                succ = select(sql, environment);
            } catch (Throwable ex) {
                LOGGER.error("mysql select error: " + ex);
                succ = false;
            }
            return succ;
        }

        /**
         * 查询
         */
        private static boolean select(String sql, ConfigurableEnvironment environment) throws Exception {

            Connection conn = null;
            PreparedStatement statement = null;
            ResultSet rs = null;
            try {

                conn = getConnection(environment);
                if (conn != null) {
                    statement = conn.prepareStatement(sql);
                    rs = statement.executeQuery();
                    if (rs != null) {
                        return true;
                    }
                }
                return false;
            } catch (Exception e) {
                String message = "database select error:" + e;
                throw new Exception(message, e);
            } finally {
                freeResource(rs, statement, conn);
            }
        }

        /**
         * 获取Connection
         */
        private static Connection getConnection(ConfigurableEnvironment environment) {
            // DB connection.
            Connection connection;

            try {

                String dbConnectUrl = environment.getProperty("spring.datasource.url")
                        + "&user=" + environment.getProperty("spring.datasource.username")
                        + "&password=" + environment.getProperty("spring.datasource.password");
                // database connection in single thread.
                Class.forName(environment.getProperty("spring.datasource.driver-class-name", "com.mysql.jdbc.Driver"));
                connection = DriverManager.getConnection(dbConnectUrl);
                LOGGER.debug("connection is ok. ");
            } catch (Exception e) {
                LOGGER.error("get connection is error: {} ", e.getMessage());
                return null;
            }
            return connection;
        }

        /**
         * 释放资源
         */
        private static void freeResource(ResultSet rs, Statement ps, Connection conn) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException ignored) {
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException ignored) {
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException ignored) {
                }
            }
        }
    }

    // ================================================================
    // Test Methods
    // ================================================================

}
